import os
from typing import Tuple

from lucommon.logger import lu_logger

import agent
import conf
from async_task.services import register_job, AsyncTask
from cert.views import gen_ca_cert
from deploy.impl import AsyncTaskFinishCreateCluster
from deploy.models import Cluster, ClusterTypeEnum
from deploy.services import etcd as ETCD
from utils import gen_static_dir, get_static_url, concurrence_requests, clean_path
from . import check_agent_status, check_concurrence_result


class AsyncTaskDeployEtcd(AsyncTask):
    def task_impl(self, etcd_config_map, pkg, application_dir, conf_dir, cert_dir,
                  etcdctl_alisa, etcd_service_path, cert_data, ) -> Tuple[int, any]:
        request_infos = {}
        for ip, config_path in etcd_config_map.items():
            request_infos[str(ip)] = {
                "url": "http://{}:{}{}".format(ip, agent.AGENT_PORT, agent.INSTALL_ETCD),
                "method": "POST",
                "json": {
                    "pkg_url": {"url": pkg.url, "extract_type": pkg.extract_type, "save_path": ""},
                    "application_dir": application_dir,
                    "etcdctl_alisa": etcdctl_alisa,
                    "depend_files": [
                        {
                            "url": get_static_url(etcd_service_path),
                            "save_path": clean_path("{}/{}".format(conf.SERVICE_DIR, ETCD.ETCD_SERVICE_NAME))
                        },  # service file
                        {
                            "url": get_static_url(config_path),
                            "save_path": clean_path("{}/{}".format(conf_dir, ETCD.ETCD_CONFIG_NAME))
                        },  # config file
                        {
                            "url": get_static_url(cert_data["cert"]["ca"]),
                            "save_path": clean_path("{}/{}".format(cert_dir, ETCD.ETCD_CA_NAME))
                        },  # etcd-ca
                        {
                            "url": get_static_url(cert_data["cert"]["etcd-server"]),
                            "save_path": clean_path("{}/{}".format(cert_dir, ETCD.ETCD_SERVER_CERT_NAME))
                        },  # etcd-server-cert
                        {
                            "url": get_static_url(cert_data["cert"]["etcd-server-key"]),
                            "save_path": clean_path("{}/{}".format(cert_dir, ETCD.ETCD_SERVER_KEY_NAME))
                        },  # etcd-server-key
                        {
                            "url": get_static_url(cert_data["cert"]["etcd-client"]),
                            "save_path": clean_path("{}/{}".format(cert_dir, ETCD.ETCD_CLIENT_CERT_NAME))
                        },  # etcd-client-cert
                        {
                            "url": get_static_url(cert_data["cert"]["etcd-client-key"]),
                            "save_path": clean_path("{}/{}".format(cert_dir, ETCD.ETCD_CLIENT_KEY_NAME))
                        },  # etcd-client-key
                    ],
                }
            }
        lu_logger.debug("request_infos:{}".format(request_infos))
        etcd_result = concurrence_requests(request_infos)
        if check_concurrence_result(etcd_result):
            return 0, etcd_result
        return -1, etcd_result


def job_deploy_etcd(params):
    cluster = params["cluster"]
    proxy_hosts = params["proxy_hosts"]
    application_dir = params["application_dir"]
    work_dir = params["work_dir"]
    cert_dir = params["cert_dir"]
    conf_dir = params["conf_dir"]
    version = params["version"]

    pkg = conf.ETCD_PACKAGE.get(str(version))
    if not pkg:
        return -1, "无适用的etcd package,valid_version:{}".format(",".join(list(conf.ETCD_PACKAGE.keys()))), {}

    # 检查agent状态
    err_ips = check_agent_status([e["ip"] for e in cluster])
    if err_ips:
        return -1, "节点检查失败,{}".format(",".join(err_ips)), {}

    # 生成存放目录
    static_dir = gen_static_dir()
    lu_logger.debug("static_dir:{}".format(static_dir))
    for etcd in cluster:
        node_dir = static_dir + "/" + etcd["ip"] + "/"
        os.mkdir(node_dir)
        lu_logger.debug("node {} dir:{}".format(etcd["ip"], node_dir))
        etcd["dir"] = node_dir

    # 签发证书
    cert_data, err = gen_ca_cert({
        "ca": {
            "CN": "etcd-ca",  # common name
            "expiry": 876000,  # ca有效时间
            "profiles": [
                {
                    "profile": "etcd",
                    "expiry": 876000,  # 签发证书有效期
                    "usages": ["signing", "key encipherment", "server auth", "client auth"],  # 签发证书用途
                }
            ],  # 指定不同签发证书使用场景
        },
        "certs": [
            {
                "name": "etcd-server",
                "CN": "etcd",
                "hosts": list(set(["localhost", "127.0.0.1"] + [e["ip"] for e in cluster] + proxy_hosts)),
                "O": "system",
                "profile": "etcd",
            },  # etcd服务端证书
            {
                "name": "etcd-client",
                "CN": "etcd",
                "hosts": list(set(["localhost", "127.0.0.1"] + [e["ip"] for e in cluster] + proxy_hosts)),
                # todo 这里etcd证书需要梳理清楚
                "O": "system",
                "profile": "etcd",
            },  # etcd客户端证书
        ],
    })
    if err:
        return -1, err, {}

    etcd_config_map = ETCD.gen_etcd_cluster_config(cluster, work_dir, cert_dir)
    etcd_service_path = ETCD.gen_etcd_service(static_dir, conf_dir)
    etcdctl_alisa = "alias etcdctl='/usr/bin/etcdctl --endpoints={ep} --cacert={ca} --cert={cert} --key={key}'\n".format(
        ep=",".join(["https://{}:2379".format(etcd["ip"]) for etcd in cluster]),
        ca=clean_path("{}/{}".format(cert_dir, ETCD.ETCD_CA_NAME)),
        cert=clean_path("{}/{}".format(cert_dir, ETCD.ETCD_CLIENT_CERT_NAME)),
        key=clean_path("{}/{}".format(cert_dir, ETCD.ETCD_CLIENT_KEY_NAME)),
    )

    config = {
        "cert_data": cert_data,
        "etcd_config_map": etcd_config_map,
        "etcd_service_path": etcd_service_path,
    }
    cluster = Cluster(
        name="etcd cluster",
        config=config,
        type=ClusterTypeEnum.ETCD
    )
    cluster.save()

    job = register_job(
        "部署etcd",
        [
            [
                AsyncTaskDeployEtcd(
                    "部署etcd",
                    {
                        "etcd_config_map": etcd_config_map,
                        "pkg": pkg,
                        "application_dir": application_dir,
                        "conf_dir": conf_dir,
                        "cert_dir": cert_dir,
                        "etcdctl_alisa": etcdctl_alisa,
                        "etcd_service_path": etcd_service_path,
                        "cert_data": cert_data,
                    }
                ),
            ],
            [
                AsyncTaskFinishCreateCluster(
                    "完成etcd集群部署",
                    {
                        "cluster": cluster,
                    }
                ),
            ],
        ]
    )
    data = {
        "job_id": job.id,
        "config": get_static_url(config),
    }

    return 0, "", data
